

/*
 * log.c
 *
 *	编写时间: 2021/7/23
 *	编写者: wmh
 *	
 */



#include "log.h"

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <stdarg.h>
#include <fcntl.h>
#include <time.h>
#include "sem.h"


/*等级名称打印列表*/
static char *			log_l[] =
{
	"OFF	", "ERROR", "WARN ", "INFO ", "DEBUG"
};

/*等级颜色打印列表*/
static char *	log_c[] =
{
	NONE_COLOR, HL_RED, HL_YELLOW, HL_GREEN, HL_CYAN
};



/************* 模块私有配置变量****************/

LOG_MODE		log_module_mode;
LOG_L_TYPE 		log_module_level ;
char *			log_module_prefix;
char *			log_module_file_prefix;

/**********************************************/

char			dir[128];
FILE *	log_fp;

int 			semid;

/*
	配置模块私有配置选项函数
	示例：log_init(LOG_MODE_FILE, LOG_L_INF, "test", "");


*/
void log_init(LOG_MODE log_module_mode_p, LOG_L_TYPE log_module_level_p, \
				char* log_module_prefix_p, char * log_module_file_prefix_p)
{
	
	log_module_mode = log_module_mode_p;
	log_module_level = log_module_level_p;
	log_module_prefix = log_module_prefix_p;
	log_module_file_prefix = log_module_file_prefix_p;

	
	if(log_module_mode == LOG_MODE_FILE){
		mkdir(COM_LOG_FILE_DIR, 0777);
		/*拼出日志文件全路径 多进程存储到同一文件时也能同步找到*/
		sprintf(dir, "%s%s%s%s", COM_LOG_FILE_DIR, COM_LOG_FILE_PREFIX, log_module_file_prefix, COM_LOG_FILE_POSTFIX);
		/*这个初始化唯一的key，自己把握*/
		semid = sem_init(1234);
		printf("log_file_path:%s\n", COM_LOG_FILE_DIR);
		
	}

}

void file_check(){

	char			dir_old[128];
	char			time_buffer[80];
	time_t rawtime;
    struct tm *info;
	unsigned int index = 0;
	
	struct stat statbuf;
	statbuf.st_size 	= 0;	
	
	if (0 == access(dir, F_OK)){
		stat(dir, &statbuf);
		if (statbuf.st_size >= LOG_MAX_FileSize){
			if(log_fp>stderr){
				fclose(log_fp);
			}
			/*先确定备份目标文件名称路径dir_old，默认与日志文件同目录*/
				/*dir_old添加保存时的时间信息*/
			time(&rawtime);
			info				= localtime(&rawtime);
			strftime(time_buffer, sizeof(time_buffer), "_%Y%m%d_%H%M%S", info);

			sprintf(dir_old, "%s%s%s%s%s", COM_LOG_FILE_DIR, COM_LOG_FILE_PREFIX, log_module_file_prefix, 
					time_buffer, COM_LOG_FILE_POSTFIX);

			/*日志文件上限小，或者日志存储过快，导致同秒就存满一个新的日志，就加序号*/
			if(0 == access(dir_old, F_OK)){
				while (1){
					sprintf(dir_old, "%s%s%s%s_%d%s", COM_LOG_FILE_DIR, COM_LOG_FILE_PREFIX, log_module_file_prefix, 
						time_buffer, index, COM_LOG_FILE_POSTFIX);

					if (0 == access(dir_old, F_OK)){
						index++;
					}else {
						break;
					}
				}
			}

			// If newpath already exists, it will be atomically replaced
			if (0 == access(dir, F_OK)){
				if (-1 == rename(dir, dir_old)){
					LOG_PRINT_ERR("rename %s to %s \n", dir, dir_old);
				}
			}


		}
	}



}



void LOG(LOG_L_TYPE enlog_level, const char * fmt, ...)
{

	
	/*判断日志等级*/
	if (log_module_level < enlog_level){
		return;
	}

	
	char			write_buf_header[512];
	char			write_buf_msg[256];
	char			time_buffer[80];

	time_t rawtime;
    struct tm *info;
	
	time(&rawtime);
	info = localtime(&rawtime);
	strftime(time_buffer, sizeof(time_buffer), "%Y/%m/%d %H:%M:%S", info);
	

	
	/*日志头部*/
	if (log_module_mode == LOG_MODE_FILE){
		/*文件不需要分级颜色打印。如果需要，自行更改*/
		sprintf(write_buf_header, "[%s] %s:%s ",time_buffer, log_l[enlog_level], 
			log_module_prefix);
	}else{
		sprintf(write_buf_header, "%s[%s] %s:%s ", log_c[enlog_level], time_buffer, log_l[enlog_level], 
			log_module_prefix);
	}
	
	
	/*日志消息*/
	va_list ap;
	va_start(ap, fmt);
	vsprintf(write_buf_msg, fmt, ap);
	va_end(ap);

	/*合并头部和消息*/
	strcat(write_buf_header, write_buf_msg);


	// 输出
	switch(log_module_mode){
	case LOG_MODE_FILE:
		/*看前加锁，给别的程序加锁*/
		sem_p(semid, 0);
		file_check();
	
		log_fp = fopen(dir, "a");
		if (NULL == log_fp){
			LOG_PRINT_ERR("%s open failed , print to stdout\n", dir);
			log_module_mode = LOG_MODE_STDOUT;
			return;
		}
		//fprintf(log_fp, write_buf_header, strlen(write_buf_header));
		fwrite(write_buf_header,1,strlen(write_buf_header),log_fp);
		
		//sem_del(semid);
		//文件关闭
		fclose(log_fp);
		//解锁
		sem_v(semid,0);
		break;

	case LOG_MODE_STDOUT:
	default: 
		log_fp = LOG_STDOUT_FD;
		fprintf(log_fp, write_buf_header, strlen(write_buf_header));
		/*颜色尾只打印屏幕*/
		printf("%s", NONE_COLOR);
		break;
	}


}



